iT邦幫忙

DAY 20
0

邊看邊學Groovy/Grails/Gradle系列 第 17

Grails-基礎GORM Query語法介紹(where)

  • 分享至 

  • xImage
  •  

繼前面已經建立Domain class以及基本頁面後,今日要跟大家分享基礎的GORM query語法,個人認為挺有Hibernate的味道,只是語法稍加改變一下而已,另外值一提的是參考書籍迄今仍未提到如何設定datasource之類的設定,是因為Grails預設適用H2這種In-memory式的資料庫,為了要demo簡易的query語法,故在啟動測試專案時,則預先寫入一些資料到資料庫,但重點是作者是在那裡或是說Grails載入的哪個時機點寫入這些資料的,這個問題就回到根本的問題上,Grails的web應用程式依舊是架構在Servlet上,只不過經過Groovy改寫後稱作Groovlet,變數有些相同例如ServletContext等,而網頁稱作GSP,廢話不多說,開始今天跟大家介紹。
servlet初始化的時候會呼叫init方法以及結束時會呼叫destroy方法,在Grails裡也是相同的,而設定Groovlet init及destory方法是定義在conf/BootStrap這個class裡,打開該檔案

class BootStrap {

    def init = { servletContext ->
    }
    def destroy = {
    }

就是init跟destroy方法,init方法亦有closure可以對servletContext做初始化,這其實就是Java的調調,只是少掉很多doGet, doPost等方法,那些都被包在Grails Framework裡。

接著看DataSource.groovy這個檔案,預設採用h2資料庫,同時可以注意到預設hibernate的second level cache是enable的,採用的是常見的Ehcache,再來是比較陌生的environments大括號括起來的地方,分成三種develop、test及production,對應到不同的環境,以目前我的程度應該只會用到test跟production,另外也可以自訂environment,其用途就需要再study了,而dbCreate就是代表存取資料庫的權限,update權限最大,可以CRUD,create、create-drop以及validate各自對應到不同權限,但有空再查吧!基本上程式要可以run的起來,dbCreate設定成update就可以進行操作了,production裡面的參數就不在說明囉,程式應該還沒大到要tune資料庫的參數才是,另外資料庫也可以換成mysql,上網google一下就有標準做法囉。

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    username = "root"
    password = "LGA2011"
	url = "jdbc:mysql://localhost:3306/grails"
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = false
    cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
}
// environment specific settings
environments {
    development {
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
            
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            
            pooled = true
            properties {
               maxActive = -1
               minEvictableIdleTimeMillis=1800000
               timeBetweenEvictionRunsMillis=1800000
               numTestsPerEvictionRun=3
               testOnBorrow=true
               testWhileIdle=true
               testOnReturn=true
               validationQuery="SELECT 1"
            }
        }
    }
}

為了要demo GORM簡單的query語法,最好新增資料的時機就是Goovlet初始化的時候,故environment我選擇production,權限最大,然後做一個判斷,如果資料庫裏面沒有任何Post則呼叫generateSimpleDate,寫入一些資料,裡面包含新增User/Post/Tag,程式碼如下:

import com.JasonMicroBlog.*
class BootStrap {

    def init = { servletContext ->
		environments{
			production{
				if(!Post.count()) generateSampleData()
			}
		}
    }
    def destroy = {
    }
	private generateSampleData() {
		
		def now = new Date()
		def graeme = new User(
				userId: "graeme",
				password: "willow",
				profile: new Profile(fullName: "Graeme Rocher", email: "graeme@nowhere.net"),
				dateCreated: now).save(failOnError: true)
		def jeff = new User(
				userId: "jeff",
				password: "sheldon",
				profile: new Profile(fullName: "Jeff Brown", email: "jeff@nowhere.net"),
				dateCreated: now).save(failOnError: true)
		def burt = new User(
				userId: "burt",
				password: "mandible",
				profile: new Profile(fullName: "Burt Beckwith", email: "burt@nowhere.net"),
				dateCreated: now).save(failOnError: true)
		def frankie = new User(
				userId: "frankie",
				password: "testing",
				profile: new Profile(fullName: "Frankie Goes to Hollywood", email: "frankie@nowhere.net"),
				dateCreated: now).save(failOnError: true)
		def sara = new User(
				userId: "sara",
				password: "crikey",
				profile: new Profile(fullName: "Sara Miles", email: "sara@nowhere.net"),
				dateCreated: now - 2).save(failOnError: true)
		def phil = new User(
				userId: "phil",
				password: "thomas",
				profile: new Profile(fullName: "Phil Potts", email: "phil@nowhere.net"),
				dateCreated: now)
		def dillon = new User(userId: "dillon",
		password: "crikey",
		profile: new Profile(fullName: "Dillon Jessop", email: "dillon@nowhere.net"),
		dateCreated: now - 2).save(failOnError: true)

		phil.addToFollowing(frankie)
		phil.addToFollowing(sara)
		phil.save(failOnError: true)

		phil.addToPosts(content: "Very first post")
		phil.addToPosts(content: "Second post")
		phil.addToPosts(content: "Time for a BBQ!")
		phil.addToPosts(content: "Writing a very very long book")
		phil.addToPosts(content: "Tap dancing")
		phil.addToPosts(content: "Pilates is killing me")
		phil.save(failOnError: true)

		sara.addToPosts(content: "My first post")
		sara.addToPosts(content: "Second post")
		sara.addToPosts(content: "Time for a BBQ!")
		sara.addToPosts(content: "Writing a very very long book")
		sara.addToPosts(content: "Tap dancing")
		sara.addToPosts(content: "Pilates is killing me")
		sara.save(failOnError: true)

		dillon.addToPosts(content: "Pilates is killing me as well")
		dillon.save(failOnError: true, flush: true)

		def postsAsList = phil.posts as List
		postsAsList[0].addToTags(user: phil, name: "groovy")
		postsAsList[0].addToTags(user: phil, name: "grails")
		postsAsList[0].dateCreated = now.updated(year: 2004, month: MAY)

		postsAsList[1].addToTags(user: phil, name: "grails")
		postsAsList[1].addToTags(user: phil, name: "ramblings")
		postsAsList[1].addToTags(user: phil, name: "second")
		postsAsList[1].dateCreated = now.updated(year: 2007, month: FEBRUARY, date: 13)

		postsAsList[2].addToTags(user: phil, name: "groovy")
		postsAsList[2].addToTags(user: phil, name: "bbq")
		postsAsList[2].dateCreated = now.updated(year: 2009, month: OCTOBER)

		postsAsList[3].addToTags(user: phil, name: "groovy")
		postsAsList[3].dateCreated = now.updated(year: 2011, month: MAY, date: 1)

		postsAsList[4].dateCreated = now.updated(year: 2011, month: DECEMBER, date: 4)
		postsAsList[5].dateCreated = now.updated(year: 2012, date: 10)
		phil.save(failOnError: true)

		postsAsList = sara.posts as List
		postsAsList[0].dateCreated = now.updated(year: 2007, month: MAY)
		postsAsList[1].dateCreated = now.updated(year: 2008, month: APRIL, date: 13)
		postsAsList[2].dateCreated = now.updated(year: 2008, month: APRIL, date: 24)
		postsAsList[3].dateCreated = now.updated(year: 2011, month: NOVEMBER, date: 8)
		postsAsList[4].dateCreated = now.updated(year: 2011, month: DECEMBER, date: 4)
		postsAsList[5].dateCreated = now.updated(year: 2012, month: AUGUST, date: 1)

		sara.dateCreated = now - 2
		sara.save(failOnError: true)

		dillon.dateCreated = now - 2
		dillon.save(failOnError: true, flush: true)
	}
}

對於上面資料的新增,test-app結果資料沒有寫進資料庫,詳細原因不清楚,debug一段時間後放棄了,直接po文在作者的討論區,看有沒有答案,故先用scaffolding出的的網頁自行新增資料

再來介紹基本的where語法

(domain class Name).where{判斷式(||, &&, >=...}.方法(get(), list())

範例就用一個Integration test介紹,程式碼如下

import grails.plugin.spock.IntegrationSpec

class QueryIntegrationTestSpec extends IntegrationSpec {

	def setup() {
	}

	def cleanup() {
	}

	void "Simple Query"() {
		when:"Specific userId is used as criterion"
		def user=User.where {userId =="Jason"}.get()
		/*注意domain class的屬性要放在左邊當作判斷式,
		*"frankie == userId"則結果會是always true
		*single record使用get()
		*/
		then:"The only one record"
		user.userId == "Jason"
	}

	void "Multiple Criteria"(){
		when: "More than one constraints are applied"
		def users=User.where{
			userId == "Jason" || password=="testing"
			}.list(sort:"userId", order: "desc")
			/*恰好有兩位的密碼都是crikey,||代表or、&&代表and
			 * 多筆記錄用list方法,跟上面的get()和在一起,
			 * 有點Hibernate的影子
			 */
			
		then:"Multiple records can be expected"
		users*.userId==["Jason", "Bob","Andrew"]
	}
	
	void "Query on a certain range"(){
		given: "Find out records on the specific range of date"
		def now = new Date()

		when: "Users are created on these dates"
		def users=User.where{
			dateCreated in (now -1)..now
			// 跟在for迴圈語法相同,in 代表某一區間
		}.list(sort:"userId", order: "desc")
		//可指定排序asc or desc
		then: "Users are retrived from database order by Id"
		users*.userId == ["Bob", "Anthony", "Andrew"]
	}
}

Integration Test Result:

| Loading Grails 2.2.3
| Configuring classpath.
| Environment set to test.....
| Packaging Grails application.....
| Packaging Grails application.....
| Compiling 1 source files...
| Running 3 spock tests... 1 of 3
| Running 3 spock tests... 2 of 3
| Running 3 spock tests... 3 of 3
| Completed 3 spock tests, 0 failed in 468ms
| Tests PASSED - view reports in D:\groovy\JasonMicroBlog\target\test-reports

從以上不難看出where()就是hibernate中的query()稍加變形而已,當然更複雜的查詢語法,Grails也支援直接下HQL,今天未介紹完的明天再繼續囉


上一篇
Grails-如何建立在Domain class中建立物件關係以及Scaffolding
下一篇
Grails-基礎GORM Query語法介紹(criteria)及簡單搜尋表單
系列文
邊看邊學Groovy/Grails/Gradle27
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言